/*******************************************************************************
 * Copyright 2007, 2009 InnovaSoft SA http://www.innovasoft.biz/
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *       http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *******************************************************************************/
 
package biz.innovasoft.ndb.index;

import java.util.Collection;
import java.util.Vector;

import org.apache.lucene.analysis.WhitespaceAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.NumberTools;
import org.apache.lucene.index.Term;
import org.apache.lucene.queryParser.ParseException;
import org.apache.lucene.queryParser.QueryParser;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.Sort;
import org.apache.lucene.search.TermQuery;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.store.SingleInstanceLockFactory;

import biz.innovasoft.ndb.RepositoryException;
import biz.innovasoft.ndb.query.QueryCriteria;

public class Searcher {

	private transient IndexManager _index;

	public Searcher () {}
	
	public Searcher(IndexManager index) {
		if (index.getDirectory().getLockFactory() == null) {
			index.getDirectory()
					.setLockFactory(new SingleInstanceLockFactory());
		}
		_index = index;
	}

	public void setIndexManager (IndexManager index) {
		if (index.getDirectory().getLockFactory() == null) {
			index.getDirectory()
					.setLockFactory(new SingleInstanceLockFactory());
		}
		_index = index;
	}
	
	public Collection<Long> searchObject(String term, String pquery) {
		Collection<Long> values = new Vector<Long>();
		try {
			IndexSearcher searcher = new IndexSearcher(_index.getDirectory());
			int freq = searcher.docFreq(new Term(term, pquery));
			Query query = new TermQuery(new Term(term, pquery));
			TopDocs docs = searcher.search(query, null, freq + 1);
			for (int t = 0; t < docs.totalHits; t++) {
				Document fh = searcher.doc(docs.scoreDocs[t].doc);
				Long id = Long.parseLong(fh.getField("oid").stringValue());
				values.add(id);
			}

			searcher.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return values;
	}

	public Collection<Long> searchObject(String querystr) {
		Collection<Long> values = new Vector<Long>();
		try {
			ExtendedQueryParser parser = new ExtendedQueryParser("field",
					new WhitespaceAnalyzer());
			parser.setLowercaseExpandedTerms(false);
			Query query = parser.parse(querystr);

			IndexSearcher searcher = new IndexSearcher(_index.getDirectory());
			TopDocs docs = searcher.search(query, null, 1000000);
			for (int t = 0; t < docs.totalHits; t++) {
				Document fh = searcher.doc(docs.scoreDocs[t].doc);
				Long id = Long.parseLong(fh.getField("oid").stringValue());
				values.add(id);
			}

			searcher.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return values;
	}

	public SearcherResult searchObject(QueryCriteria query) {
		String querystr = query.toString();
		Sort sort = new Sort(query.getSortFields());
		SearcherResult result = new SearcherResult ();
		
		try {
			int from = (query.getPage() == 0) ? query.getPage() : query.getPage() * query.getMaxResults();
			int to = from + query.getMaxResults();
			
			QueryParser parser = new QueryParser("field",
					new WhitespaceAnalyzer());
			parser.setLowercaseExpandedTerms(false);
			Query _query = null;
			try {
				_query = parser.parse(querystr);
			} catch (ParseException e) {
				throw new SyntaxErrorException ("Error parsing query.", e);
			}

			IndexSearcher searcher = new IndexSearcher(_index.getDirectory());
			TopDocs docs = searcher.search(_query, null, to, sort);
			
			result.setTotalHits(docs.totalHits);
			if (docs.totalHits > 0) {
				if ( from > docs.totalHits ) return result;
				if ( to > docs.totalHits ) to = docs.totalHits;
				for (int t = from; t < to; t++) {
					Document fh = searcher.doc(docs.scoreDocs[t].doc);
					Long id = NumberTools.stringToLong(fh.getField("oid").stringValue());
					result.getOids().add(id);
				}
				result.setMinRange(from);
				result.setMaxRange(to);
				result.setMaxResults(query.getMaxResults());
			}

			searcher.close();
		} catch (Exception e) {
			throw new RepositoryException (e);
		}
		return result;
	}

	public void deleteIndex(Long oid) {
		IndexSearcher searcher = null;
		try {
			searcher = new IndexSearcher(_index.getDirectory());
		} catch (Exception e) {
			return;
		}
		try {
			searcher.getIndexReader().deleteDocuments(
						new Term("oid", NumberTools.longToString(oid)));
			searcher.close();
		} catch (Exception e) {
			throw new IndexException("Object with oid: " + oid
					+ ", could not be deleted from index.");
		}
	}

}
